<!--
 *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree.
-->

<!--
`<line-chart>` is used to display a line chart updating in real-time to the user
in an efficient way and without locking the js thread for too long.

It is not a very advanced or a pretty line chart render, but it is very
specialized for the testrtc use case where delaying the JS thread incurs delays
on measuring the round-trip time.
-->
<link rel="import" href="../../polymer/polymer.html">
<polymer-element name="line-chart">
  <template>
    <div style="width:300px; margin:auto;">
      <canvas id="canvas" width="240" height="150"></canvas>
    </div>
  </template>
  <script>
    var interval = 0;
    Polymer({
      x: [],
      y: [],
      yScale: [0, 600],
      yLabels: [0, 50, 100, 150, 200, 250, 300, 350, 400, 450, 500],
      xStart: null,
      xOffset: null,
      lastSlowRender: null,
      addDatapoint: function(timestamp, value) {
        var startRender = window.performance.now();
        this.ctx = this.$.canvas.getContext('2d');

        var index = this.x.length;
        this.x.push(timestamp / 100.0 * 2);
        this.y.push(this.calculateY(value));

        var xCoord = this.x[index] - this.xStart;
        if (this.xStart === null || xCoord > this.$.canvas.width) {
          // First point added or a point added that clears the chart.
          this.setupChart();
          this.xStart = this.x[index] - this.xOffset;
        } else {
          var oldXCoord = this.x[index - 1] - this.xStart;
          this.ctx.save();
          this.ctx.beginPath();
          this.ctx.fillStyle = this.dotColor(this.y[index - 1]);
          this.ctx.fillRect(oldXCoord - 1.5, this.y[index - 1] - 1.5, 3, 3);
          this.ctx.moveTo(oldXCoord, this.y[index - 1]);
          this.ctx.lineTo(xCoord, this.y[index]);
          this.ctx.stroke();
          this.ctx.closePath();
          this.ctx.restore();
        }

        var now = window.performance.now();
        this.maybeAlertAboutRenderPerformance(now - startRender);
      },

      maybeAlertAboutRenderPerformance: function(renderMs) {
        if (renderMs < 5) {
          return;
        }
        var now = window.performance.now();
        if (this.lastSlowRender === null ||
            now - this.lastSlowRender > 5000) {
          this.lastSlowRender = now;
          console.log('Updating the graph was slow and might affect results.'
                      + ' Graph update took ' + renderMs + ' ms');
        }
      },

      setupChart: function() {
        this.ctx.clearRect (0 , 0, this.$.canvas.width, this.$.canvas.height);
        this.ctx.lineWidth = window.devicePixelRatio;
        this.ctx.strokeStyle = 'grey';

        this.ctx.save();

        this.ctx.lineWidth = window.devicePixelRatio;
        this.ctx.strokeStyle = 'lightgray';

        if (this.ctx.lineWidth % 2) {
          this.ctx.translate(0.5, 0.5);
        }

        this.ctx.textAlign = 'right';
        this.ctx.textBaseline = 'middle';

        this.ctx.beginPath();
        this.xOffset = 0;
        for (var index = 0; index != this.yLabels.length; index++) {
          var yLabel = this.yLabels[index] + ' ms ';
          var yLabelWidth = this.ctx.measureText(yLabel).width;
          this.xOffset = Math.max(this.xOffset, yLabelWidth);
        }

        for (var index = 0; index != this.yLabels.length; index++) {
          var y = this.calculateY(this.yLabels[index]);
          this.ctx.moveTo(this.xOffset - 3, y);
          if (index % 2 == 1) {
            this.ctx.lineTo(this.xOffset + 3, y);
          } else {
            this.ctx.lineTo(this.$.canvas.width, y);
          }
        }
        var topY = this.calculateY(this.yLabels[this.yLabels.length - 1]);
        var bottomY = this.calculateY(0);
        this.ctx.moveTo(this.xOffset, topY);
        this.ctx.lineTo(this.xOffset, bottomY);
        this.ctx.lineTo(this.$.canvas.width - 1, bottomY);
        this.ctx.lineTo(this.$.canvas.width - 1, topY);
        this.ctx.stroke();
        this.ctx.closePath();

        for (var index = 0; index != this.yLabels.length; index++) {
          var y = this.calculateY(this.yLabels[index]);
          if (index % 2 == 0) {
            this.ctx.fillText(this.yLabels[index] + ' ms ', this.xOffset, y);
          }
        }

        this.ctx.restore();
      },

      dotColor: function(value) {
        return value < 300 ? 'green' : 'red';
      },

      calculateY: function(value) {
        if (value > this.yScale[1]) { value = this.yScale[1] - 10; }
        var y = (value - this.yScale[0])/(this.yScale[1] - this.yScale[0]);
        return this.$.canvas.height * (1 - y) - 5;
      }
    });
  </script>
</polymer-element>
